package com.oxygen.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.danga.MemCached.MemCachedClient;
import com.danga.MemCached.SockIOPool;

public class MemcachedCluster {
	private static Object LOCK = new Object();
	private final static Log loger = LogFactory.getLog(MemcachedCluster.class);
	private Properties properties;
	private MemCachedClient memCachedMaster;
	private MemCachedClient memCachedSlave;
	public final static int SESSION_SECOND = 3600 * 24;
	public final static int TWO_HOUR_SECOND = 7200;
	public final static int FIVE_HOUR_SECOND = 5 * 60 * 60;
	public final static int TEN_HOUR_SECOND = 10 * 60 * 60;
	public final static String memcacheMapKey = "MEMACACHE_MAP_KEY";
	private static String[] master = null;
	private static String[] slave = null;
	private static boolean flagRestart = true;
	private static MemcachedCluster instance = null;

	private MemCachedClient init(String[] servers) {
		try {
			if (servers != null && servers.length > 0) {
				SockIOPool pool = SockIOPool.getInstance(servers.toString());
				if (pool != null) {
					pool.setServers(servers);
					pool.setFailover(true);
					pool.setInitConn(10);
					pool.setMinConn(5);
					pool.setMaxConn(50);
					pool.setMaintSleep(30);
					pool.setNagle(false);
					pool.setSocketTO(30000);
					pool.setBufferSize(1024 * 1024 * 5);
					pool.setAliveCheck(true);
					pool.initialize(); /* 建立MemcachedClient实例 */
				}
				return new MemCachedClient(servers.toString());
			}

		} catch (Exception ex) {
			loger.error(ex, ex);
		}
		return null;
	}

	private MemcachedCluster() {
		try {
			properties = new Properties();
			// Resource resource = new
			// ClassPathResource("memcached.properties");
			// properties.load(resource.getInputStream());
			InputStream inStream = this.getClass().getClassLoader().getResourceAsStream("memcached.properties");
			properties.load(inStream);
			// 数据缓存服务器，“,”表示配置多个memcached服务
			master = properties.getProperty("memcache.cache.server.master").split(",");
			slave = properties.getProperty("memcache.cache.server.slave").split(",");

			this.memCachedMaster = init(master);
			this.memCachedSlave = init(slave);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public MemCachedClient getMemCachedMasterClient() {
		return this.memCachedMaster;
	}

	public MemCachedClient getMemCachedSlaveClient() {
		return this.memCachedSlave;
	}

	private boolean isCacheEnabled() {
		boolean useCache = false;
		try {
			useCache = Boolean.valueOf(properties.getProperty("cache.enable"));
		} catch (Exception e) {
			useCache = false;
			loger.info("Please enable memcached");
		}
		return useCache;
	}

	/**
	 * 改用嵌套类静态实始化
	 * 
	 * @return
	 */
	public static MemcachedCluster getInstance() {
		if (instance == null) {
			synchronized (LOCK) {
				if (instance == null) {
					instance = new MemcachedCluster();
				}
			}
		}
		return instance;
	}

	/**
	 * 替换
	 * 
	 * @param key
	 * @param seconds
	 *            过期秒数
	 * @param obj
	 * @return
	 */
	public boolean replace(String key, int seconds, Object obj) {
		if (key == null || "".equals(key)) {
			return false;
		}
		if (obj == null) {
			return true;
		}
		try {
			if (isCacheEnabled()) {
				Date expDate = getDateAfter(seconds);
				boolean result = replaceValue(key, obj, expDate);
				loger.debug("SET A OBJECT: KEY:" + key + ", OBJ:" + obj + ", exp:" + DateTimeUtil.formatDateTime(expDate) + ", result:" + result);
				return result;
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			loger.error(e, e);
		}
		return false;
	}

	/**
	 * @param key
	 * @param obj
	 * @param expDate
	 * @return
	 */
	private boolean replaceValue(String key, Object value, Date expDate) {
		boolean resultMaster = memCachedMaster.replace(key, value, expDate);
		boolean resultSlave = this.memCachedSlave.replace(key, value, expDate);
		return resultMaster && resultSlave;
	}

	/**
	 * set 单位秒
	 * 
	 * @param key
	 * @param expSecond
	 * @param obj
	 * @return
	 */
	public boolean set(String key, int expSecond, Object obj) {
		return this.set(key, getDateAfter(expSecond), obj);
	}

	/**
	 * 将KEY保存到memcache中
	 * 
	 * @param key
	 * @param exp
	 * @param obj
	 * @return
	 */
	public boolean set(String key, Date exp, Object obj) {
		if (key == null || "".equals(key)) {
			return false;
		}
		if (obj == null) {
			return true;
		}
		try {
			if (isCacheEnabled()) {
				boolean result = setValue(key, obj, exp);
				loger.debug("SET A OBJECT: KEY:" + key + ", OBJ:" + obj + ", exp:" + DateTimeUtil.formatDateTime(exp) + ", result:" + result);
				return result;
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			loger.error(e, e);
		}
		return false;
	}

	/**
	 * @deprecated 此方法不建议使用
	 * 
	 *             保存key和描述信息；
	 * 
	 * @param key
	 * @param second
	 *            （单位：秒）
	 * @param obj
	 * @return
	 */
	@Deprecated
	public boolean setWithDis(String key, int seconds, Object obj, String discript) {
		if (key == null || "".equals(key)) {
			return false;
		}
		if (obj == null) {
			return true;
		}
		try {
			if (isCacheEnabled()) {
				Date expDate = getDateAfter(seconds);
				this.putKeyDisMap(key, discript);
				boolean result = setValue(key, obj, expDate);
				loger.debug("SET A OBJECT: KEY:" + key + ", OBJ:" + obj + ", expDate:" + DateTimeUtil.formatDateTime(expDate));
				return result;
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			loger.error(e, e);
		}
		return false;
	}

	/**
	 * @param key
	 * @param obj
	 * @param expDate
	 * @return
	 */
	private boolean setValue(String key, Object value, Date expDate) {
		boolean resultMaster = memCachedMaster.set(key, value, expDate);
		boolean resultSlave = this.memCachedSlave.set(key, value, expDate);
		return resultMaster && resultSlave;
	}

	/**
	 * 把相应的Key值和描述存到此方法中；
	 * 
	 * @param key
	 * @param discript
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private boolean putKeyDisMap(String key, String discript) {
		Map<String, String> memMap;
		Object obj = memCachedMaster.get(memcacheMapKey);
		if (obj == null) {
			memMap = new HashMap<String, String>();
		} else {
			memMap = (HashMap<String, String>) obj;
		}
		memMap.put(key, discript);
		memCachedMaster.set(memcacheMapKey, memMap, getDateAfter(60 * 60 * 48));

		return true;
	}

	/**
	 * 取
	 * 
	 * @param key
	 * @return
	 */
	public Object get(String key) {
		try {
			if (isCacheEnabled()) {
				Object obj = getValue(key);
				loger.debug("GET A OBJECT: KEY:" + key + " OBJ:" + (obj == null ? "null" : obj.toString()));
				return obj;
			}
		} catch (Exception e) {
			e.printStackTrace();
			loger.error(e, e);
		}
		return null;
	}

	/**
	 * @param key
	 * @return
	 */
	private Object getValue(String key) {
		Object slaveValue = memCachedSlave.get(key);
		Object masterValue = memCachedMaster.get(key);
		System.out.println("#####################slave:" + slaveValue + ";;;;;;master:" + masterValue);
		if (slaveValue == null && masterValue != null) {
			if (flagRestart) {
				this.checkSlave();
			}
			return masterValue;
		}
		return slaveValue;
	}

	/**
	 * 取
	 * 
	 * @param key
	 * @return
	 */
	public boolean remove(String key) {
		if (key == null || "".equals(key)) {
			return false;
		}
		try {
			if (isCacheEnabled()) {
				loger.info("delete memcached key: " + key);
				return delete(key);
			}
		} catch (Exception e) {
			e.printStackTrace();
			loger.error(e, e);
		}
		return true;
	}

	/**
	 * @param key
	 * @return
	 */
	private boolean delete(String key) {
		boolean resultMaster = memCachedMaster.delete(key);
		boolean resultSlave = this.memCachedSlave.delete(key);
		return resultMaster && resultSlave;
	}

	/**
	 * 获得当前开始活参数秒的时间日期
	 * 
	 * @Title: getDateAfter
	 * @Description:
	 * @param
	 * @return Date 返回类型
	 * @throws
	 */
	private static Date getDateAfter(int second) {
		Calendar cal = Calendar.getInstance();
		cal.add(Calendar.SECOND, second);
		return cal.getTime();
	}

	private void checkSlave() {
		new Thread(new Runnable() {
			@Override
			public void run() {
				for (String host : slave) {
					try {
						String[] ip = host.split(":");
						SocketChannel sock = SocketChannel.open();
						sock.socket().connect(new InetSocketAddress(ip[0], Integer.valueOf(ip[1])), 60 * 1000);
						Socket result = sock.socket();
						if (result == null) {
							System.out.println("服务器IP有问题：" + host);
						}
					} catch (IOException e) {
						e.printStackTrace();
						System.out.println("服务器IP有问题：" + host);
					}

				}
				flagRestart = false;
			}
		}).start();
	}

	public void copyMasterToSlave(String host) {
		MemCachedClient mcc = MemcachedCluster.getInstance().getMemCachedMasterClient();
		List<String> list = new ArrayList<String>();
		Map<String, Map<String, String>> items = mcc.statsItems();
		for (Iterator<String> itemIt = items.keySet().iterator(); itemIt.hasNext();) {
			String itemKey = (String) itemIt.next();
			Map<String, String> maps = items.get(itemKey);
			for (Iterator<String> mapsIt = maps.keySet().iterator(); mapsIt.hasNext();) {
				String mapsKey = (String) mapsIt.next();
				String mapsValue = (String) maps.get(mapsKey);
				if (mapsKey.endsWith("number")) {
					String[] arr = mapsKey.split(":");
					int slabNumber = Integer.valueOf(arr[1].trim());
					int limit = Integer.valueOf(mapsValue.trim());
					Map<String, Map<String, String>> dumpMaps = mcc.statsCacheDump(slabNumber, limit);
					for (Iterator<String> dumpIt = dumpMaps.keySet().iterator(); dumpIt.hasNext();) {
						String dumpKey = (String) dumpIt.next();
						Map<String, String> allMap = dumpMaps.get(dumpKey);
						for (Iterator<?> allIt = allMap.keySet().iterator(); allIt.hasNext();) {
							String allKey = (String) allIt.next();
							list.add(allKey.trim());
						}
					}
				}
			}
		}
	}

	public static void main(String[] args) throws Exception {
		// Map<String, String> map = (Map<String, String>)
		// MemcachedCluster.getInstance().get("af");
		// if (map == null) {
		// System.out.println("before  keys: " + map);
		// map = new HashMap<String, String>();
		// for (int i = 0; i < 1; i++) {
		// Random r = new Random(System.currentTimeMillis());
		// String key = "KEY_" + r.nextLong();
		// System.out.println("keys: " + key);
		//
		// byte[] bt = new byte[0];
		// String value = new String(bt, "UTF-8");
		// for (int j = 0; j < 10; j++) {
		// value = value + "abc";
		// }
		// map.put(key, value);
		// }
		//
		// boolean a = MemcachedCluster.getInstance().set("bbbbbbbbbb",
		// MemcachedCluster.TWO_HOUR_SECOND, "abc");
		//
		// // boolean b = MemcachedCluster.getInstance().set("ae2",
		// MemcachedCluster.TWO_HOUR_SECOND, "edf");
		// System.out.println(a);

		// System.out.println(MemcachedCluster.getInstance().get("bbbbbbbbbb"));
		// System.out.println(MemcachedCluster.getInstance().get("ae2"));

		/*
		 * Map<String, Map<String, String>> map =
		 * MemcachedCluster.getInstance().
		 * getMemCachedMasterClient().statsItems(); for (String key :
		 * map.keySet()) { System.out.println(key + "###" + map.get(key)); for
		 * (String key2 : map.get(key).keySet()) { System.out.println(key2 +
		 * "###" + map.get(key).get(key2)); } }
		 */

		// MemcachedCluster.getInstance().set("MSG-5-96", 0, 0);
		System.out.println(DateTimeUtil.formatDateTime(new Date(1376394021L)));
		// getAllKeys();
		// keySet();
	}

	public static List<String> getAllKeys() {
		MemCachedClient mcc = MemcachedCluster.getInstance().getMemCachedMasterClient();
		List<String> list = new ArrayList<String>();

		Map<String, Map<String, String>> items = mcc.statsItems();
		for (Iterator<String> itemIt = items.keySet().iterator(); itemIt.hasNext();) {
			String itemKey = (String) itemIt.next();

			// System.out.println("----------------------------");
			// System.out.println("items:" + itemKey);//items:127.0.0.1:11211
			// System.out.println("============================");

			Map<String, String> maps = items.get(itemKey);
			for (Iterator<String> mapsIt = maps.keySet().iterator(); mapsIt.hasNext();) {
				String mapsKey = (String) mapsIt.next();
				String mapsValue = (String) maps.get(mapsKey);

				// System.out.println("----------------------------");
				// System.out.println("maps:" + mapsKey);//items:15:number
				// System.out.println("maps:" + mapsValue);//50
				// System.out.println("============================");

				if (mapsKey.endsWith("number")) {// memcached key 类型
													// item_str:integer:number_str
					String[] arr = mapsKey.split(":");
					int slabNumber = Integer.valueOf(arr[1].trim());
					int limit = Integer.valueOf(mapsValue.trim());

					Map<String, Map<String, String>> dumpMaps = mcc.statsCacheDump(slabNumber, limit);
					for (Iterator<String> dumpIt = dumpMaps.keySet().iterator(); dumpIt.hasNext();) {
						String dumpKey = (String) dumpIt.next();

						// System.out.println("----------------------------");
						// System.out.println("dumpMaps:" +
						// dumpKey);//127.0.0.1:11211
						// System.out.println("============================");

						Map<String, String> allMap = dumpMaps.get(dumpKey);
						for (Iterator<?> allIt = allMap.keySet().iterator(); allIt.hasNext();) {
							String allKey = (String) allIt.next();
							list.add(allKey.trim());
							System.out.println("key:" + allKey);
							System.out.println("values:" + allMap.get(allKey));
						}
					}
				}
			}
		}
		return list;
	}
}
